package net.funtip.ormgenerator.generator;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import net.funtip.ormgenerator.model.Entity;
import net.funtip.ormgenerator.model.Model;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class ClassGenerator {
	
	private static final String _JAVA = ".java";

	private Logger log = LoggerFactory.getLogger(this.getClass());

	private static final String TEMPLATE_BASE_DIR = "/templates/";

	private boolean generateJpa;
	private boolean generateObjectify;
	private boolean generateDao;
	
	private List<String> generatedFiles;
	
	public ClassGenerator(boolean generateJpa, boolean generateObjectify, boolean generateDao) {
		super();
		this.generateJpa = generateJpa;
		this.generateObjectify = generateObjectify;
		this.generateDao = generateDao;
		this.generatedFiles = new ArrayList<String>();
	}

	public void generateClassFiles(String outputBaseDir, Model model) {
		for (Entity e: model.getEntities()) {
			log.info("generating class file for entity "+e);
			String dir = outputBaseDir + "/"+ packageNameToPath(e.getEntityPackageName()) + "/";
			createDirectory(dir);
			generateFile("entityInterface.ftl", dir + e.getName() + _JAVA, e);
			if (generateObjectify) {
				generateFile("entityObjectifyImpl.ftl", dir + e.getObjectifyName() + _JAVA, e);
			}
			if (generateJpa) {
				generateFile("entityJpaImpl.ftl", dir + e.getJpaName() + _JAVA, e);
			}
			
			// generating Data Access Objects (DAOs)
			if (generateDao && !e.isAbstractSuperclass()) {
				dir = outputBaseDir + "/"+ packageNameToPath(e.getDaoPackageName()) + "/";
				createDirectory(dir);
				generateFile("daoInterface.ftl", dir + e.getDaoName() + _JAVA, e);
				if (generateObjectify) {
					generateFile("daoObjectifyImpl.ftl", dir + e.getObjectifyDaoName() + _JAVA, e);
				}
				if (generateJpa) {
					generateFile("daoJpaImpl.ftl", dir + e.getJpaDaoName() + _JAVA, e);
				}
			}
		}
	}
	
	private void createDirectory(String dir) {
		new File(dir).mkdirs();
	}

	private String packageNameToPath(String packageName) {
		if (packageName == null) return null;
		return packageName.replace(".", "/");
	}

	private void generateFile(String templateFile, String fileName, Object root) {
		Configuration cfg = new Configuration();
		cfg.setDefaultEncoding("UTF-8");
		cfg.setClassForTemplateLoading(this.getClass(), TEMPLATE_BASE_DIR);
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		
		try {
			Template temp = cfg.getTemplate(templateFile);
			Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), "UTF-8"));
	        temp.process(root, out);
	        out.flush();
	        generatedFiles.add(fileName);
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		} catch (TemplateException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	public List<String> getGeneratedFiles() {
		return generatedFiles;
	}

}
